/**
 * @addtogroup brd_flash
 * brd_flash
 * @{
 */
/**
 * @file brd_flash.h
 * @brief Flash板级层
 * @par 修改日志
 * <table>
 * <tr><th>Date <th>Version <th>Author <th>Description
 * <tr><td>2020-09-30 <td>1.0 <td>软件工程院 <td>创建初始版本
 * <tr><td>2021-04-27 <td>1.1 <td>软件工程院 <td>增加擦除整片及定位区域接口
 * @par 示例
 * @code 
 * 创建一个设备.
   const Brd_TFlashInfo *info;
   Brd_Thandle handle = Brd_FlashCreateEx(0);
   ...
   Brd_FlashPowerSupplyEx(handle, kBrd_PowerSupplyOn);
   Brd_FlashOpenEx(handle);
   ...
   info = Brd_FlashGetInfo(handle);
   Brd_FlashErase(handle, offset, size);
   Brd_FlashWrite(handle, offset, data, size);
   ...
   Brd_FlashCloseEx(handle);
   Brd_FlashPowerSupplyEx(handle, kBrd_PowerSupplyOff);
   ...
   Brd_FlashDestoryEx(handle);
 * @endcode
 * @copyright 杭州鸿泉物联网技术股份有限公司
 */

#ifndef _BRD_FLASH_H_
#define _BRD_FLASH_H_

#include <ofc_types.h>
#include "brd_common.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * 芯片容量相关的信息
 * @note 对于某些FLASH扇区大小变化的情况比如GD32F4xx,STM32F4xx, 获取的信息不具有参考意义
 * @note 扇区大小为: pages_per_sector * page_size 字节
 *       页大小为: page_size 字节
 *       总扇区个数为: block_count * sectors_per_block 个
 *       总页个数为: block_count * sectors_per_block * pages_per_sector 个
 *       总容量为: block_count * sectors_per_block * pages_per_sector * page_size 字节
 */
struct Brd_TFlashInfoTag
{
    UInt32 block_count;             ///< 芯片包含的块数
    UInt32 sectors_per_block;       ///< 每个块包含的扇区数
    UInt32 pages_per_sector;        ///< 每个扇区包含的页数
    UInt32 page_size;               ///< 每个页包含的字节数
};
typedef struct Brd_TFlashInfoTag Brd_TFlashInfo;

/**
 * 擦除区域信息
 * 用于某些Flash扇区大小变化的情况比如GD32F4xx,STM32F4xx,这类Flash并非统一的尺寸
 * 比如:
 * +------------------+
 * |       5个16KB    |  {.offset=x, size= 16KB,.blocks=5 }
 * +------------------+
 * |       8个32KB    |  {.offset=x, size= 32KB,.blocks=8 }
 * +------------------+
 * |       2个64KB    |  {.offset=x, size= 64KB,.blocks=2 }
 * +------------------+
 * |       7个128KB   |  {.offset=x, size=128KB,.blocks=7 }
 * +------------------+
 */
struct Brd_TFlashRegionInfoTag
{
    UInt32 start;  ///< 该区域的起始偏移地址
    UInt32 size;  ///< 该区域内擦除单元的尺寸
    UInt32 blocks;  ///< 该区域内存在多少个这样的擦除单元 */
};
typedef struct Brd_TFlashRegionInfoTag Brd_TFlashRegionInfo;

/**
 * 根据标识创建句柄
 * @param id: 标识, 参见[brd_flash_def](@ref Brd_TFlashIdTag)
 * @return 当返回值为非 NULL 时, 表示创建成功, \n
 *         当返回值为 NULL 时, 表示创建失败, 原因为参数错误
 */
Brd_THandle Brd_FlashCreateEx(Int32 id);

/**
 * 销毁句柄
 * @param handle: 句柄
 * @return 当返回值 >= 0 时, 表示销毁成功 \n
 *         当返回值 < 0 时, 表示销毁失败, 参见[brd_common_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_FlashDestoryEx(Brd_THandle handle);

/**
 * Flash设备供电
 * @note 设备操作的前提, 需要先供电, 所有操作完成后需要停止供电以降低功耗
 * @param handle: 句柄
 * @param power : 设备供电类型, 参见[brd_common_def](@ref Brd_TPowerSupplyTag)
 * @return 当返回值 >= 0 时, 表示控制成功 \n
 *         当返回值 < 0 时, 表示控制失败参见[brd_common_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_FlashPowerSupplyEx(Brd_THandle handle, Int32 power);

/**
 * 打开Flash设备
 * @param handle: 句柄
 * @return 当返回值 >= 0 时, 表示打开成功 \n
 *         当返回值 < 0 时, 表示打开失败, 参见[brd_common_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_FlashOpenEx(Brd_THandle handle);

/**
 * 设备关闭
 * @param handle: 句柄
 * @return 当返回值 >= 0 时, 表示关闭成功 \n
 *         当返回值 < 0 时, 表示关闭失败, 参见[brd_common_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_FlashCloseEx(Brd_THandle handle);

/**
 * 根据标识获取句柄
 * @note 逐渐废除此接口, 使用Brd_FlashCreate替换
 * @param id: 标识, 参见[brd_def](@ref Brd_TFlashIdTag)
 * @return 当返回值为非 NULL 时, 表示成功, \n
 *         当返回值为 NULL 时, 表示失败, 原因为参数错误, 或者需要调用Brd_FlashCreate
 */
Brd_THandle Brd_FlashHandle(Int32 id);

/**
 * 获取标识
 * @param handle: 句柄
 * @return 返回用于创建句柄的标识
 */
Int32 Brd_FlashId(Brd_THandle handle);

/**
 * 获取芯片容量相关的信息
 * @param handle: 句柄
 * @return 返回芯片容量相关的信息.参见[brd_flash](@ref Brd_TFlashInfoTag)
 */
const Brd_TFlashInfo *Brd_FlashGetInfo(Brd_THandle handle);

/**
 * 读取Flash数据
 * @param handle: 句柄
 * @param offset: 读取的数据在Flash中的偏移位置
 * @param buf: 存放数据的缓冲区
 * @param size: 缓冲区长度(长度不受限制,可以一次性读出所有数据)
 * @return 当返回值 >= 0 时, 表示实际读取到的数据个数 \n
 *         当返回值 < 0 时, 表示设置失败, 参见[brd_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_FlashRead(Brd_THandle handle, UInt32 offset, void *buf, UInt32 size);

/**
 * 写数据到Flash
 * @param handle: 句柄
 * @param offset: 写入位置的偏移位置
 * @param data: 数据指针
 * @param size: 数据长度
 * @return 当返回值 >= 0 时, 表示实际写入的数据个数 \n
 *         当返回值 < 0 时, 表示写入失败, 参见[brd_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_FlashWrite(Brd_THandle handle, UInt32 offset, const void *data, UInt32 size);

/**
 * 定位擦除区域
 * @note: 通过偏移地址给出地址所处的擦除区域信息
 * @param handle: 句柄
 * @param offset: 写入位置的偏移位置
 * @param info: 偏移地址对应的区域信息
 * @return 当返回值 >= 0 时, 表示成功 \n
 *         当返回值 < 0 时, 表示失败, 参见[brd_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_FlashLocateEraseRegion(Brd_THandle handle, UInt32 offset, Brd_TFlashRegionInfo *info);

/**
 * 擦除扇区
 * @note: 擦除后不校验数据是否全是0xFF
 *     -# 对于 FLASH 扇区大小不一致的芯片, 使用时请先定位擦除扇区信息
 * @param handle: 句柄
 * @param offset: 写入位置的偏移位置
 * @param size: 擦除大小
 * @return 当返回值 >= 0 时, 表示擦除成功的扇区数量 \n
 *         当返回值 < 0 时, 表示擦除失败, 参见[brd_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_FlashErase(Brd_THandle handle, UInt32 offset, UInt32 size);

/**
 * 整片擦除
 * @note: 擦除后不校验数据是否全是0xFF
 * @param handle: 句柄
 * @return 当返回值 >= 0 时, 表示成功\n
 *         当返回值 < 0 时, 表示失败, 参见[brd_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_FlashEraseChip(Brd_THandle handle);

#ifdef BRD_FLASH_LARGE_OFFSET64
/**
 * 读取Flash数据
 * @param handle: 句柄
 * @param offset: 读取的数据在Flash中的偏移位置
 * @param buf: 存放数据的缓冲区
 * @param size: 缓冲区长度(长度不受限制,可以一次性读出所有数据)
 * @return 当返回值 >= 0 时, 表示实际读取到的数据个数 \n
 *         当返回值 < 0 时, 表示设置失败, 参见[brd_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_FlashRead64(Brd_THandle handle, UInt64 offset, void *buf, UInt32 size);

/**
 * 写数据到Flash
 * @param handle: 句柄
 * @param offset: 写入位置的偏移位置
 * @param data: 数据指针
 * @param size: 数据长度
 * @return 当返回值 >= 0 时, 表示实际写入的数据个数 \n
 *         当返回值 < 0 时, 表示写入失败, 参见[brd_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_FlashWrite64(Brd_THandle handle, UInt64 offset, const void *data, UInt32 size);

/**
 * 定位擦除区域
 * @note: 通过偏移地址给出地址所处的擦除区域信息
 * @param handle: 句柄
 * @param offset: 写入位置的偏移位置
 * @param info: 偏移地址对应的区域信息
 * @return 当返回值 >= 0 时, 表示成功 \n
 *         当返回值 < 0 时, 表示失败, 参见[brd_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_FlashLocateEraseRegion64(Brd_THandle handle, UInt64 offset, Brd_TFlashRegionInfo *info);

/**
 * 擦除扇区
 * @note: 擦除后不校验数据是否全是0xFF
 *     -# 对于 FLASH 扇区大小不一致的芯片, 使用时请先定位擦除扇区信息
 * @param handle: 句柄
 * @param offset: 写入位置的偏移位置
 * @param size: 擦除大小
 * @return 当返回值 >= 0 时, 表示擦除成功的扇区数量 \n
 *         当返回值 < 0 时, 表示擦除失败, 参见[brd_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_FlashErase64(Brd_THandle handle, UInt64 offset, UInt32 size);
#endif

/**
 * 挂载分区
 * @note
 *      分区的起始地址和尺寸已由配置文件指定
 * @param handle: 句柄
 * @return 当返回值 >= 0 时, 表示成功\n
 *         当返回值 < 0 时, 表示失败, 参见[brd_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_FlashMount(Brd_THandle handle);

/**
 * 卸载分区
 * @param handle: 句柄
 * @return 当返回值 >= 0 时, 表示成功\n
 *         当返回值 < 0 时, 表示失败, 参见[brd_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_FlashUnmount(Brd_THandle handle);

/**
 * 格式化分区
 * @note
 *      分区的起始地址和尺寸已由配置文件指定
 * @param handle: 句柄
 * @return 当返回值 >= 0 时, 表示成功\n
 *         当返回值 < 0 时, 表示失败, 参见[brd_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_FlashMkfs(Brd_THandle handle);

/**
 * 查询存在的错误
 * @param handle: 句柄
 * @errors: 当errors==0时, 表示无错误. 否则, 表示有错误, 不同的位代表不同的错误
 * @return 当返回值 >= 0 时, 表示成功\n
 *         当返回值 < 0 时, 表示失败, 参见[brd_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_FlashGetErrors(Brd_THandle handle, UInt32 *errors);

/// RAW NAND FLASH特殊操作~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#ifdef BRD_FLASH_RAW_NAND

struct Brd_TFlashRawNandInfoTag
{
    UInt16 blocks;              ///< 芯片包含的块数
    UInt16 page_per_block;      ///< 每个块包含的页数
    UInt16 page_size;           ///< 每个页包含的字节数
    UInt16 spare_size;          ///< 每页包含的spare大小; 如果芯片自带ECC校验,则剔除芯片已经使用的spare大小.
};
typedef struct Brd_TFlashRawNandInfoTag Brd_TFlashRawNandInfo;

/**
 * 获取芯片容量相关的信息
 * @param handle: 句柄
 * @param info: 芯片容量相关的信息.参见[brd_flash](@ref Brd_TFlashRawNandInfo)
 * @return 当返回值 >= 0 时, 表示成功 \n
 *         当返回值 < 0 时, 表示失败, 参见[brd_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_FlashGetRawNandInfo(Brd_THandle handle, const Brd_TFlashRawNandInfo **info);

/**
 * 读取Flash数据
 * @param handle: 句柄
 * @param page: 页编号
 * @param p_buf: 页数据指针
 * @param p_size: 页数据大小, 不能超过Brd_TFlashRawNandInfo.page_size
 * @param s_buf: spare数据指针
 * @param s_size: spare数据大小, 不能超过Brd_TFlashRawNandInfo.spare_size
 * @return 当返回值 >= 0 时, 表示实际读取到的数据个数 \n
 *         当返回值 < 0 时, 表示设置失败, 参见[brd_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_FlashReadRawNand(Brd_THandle handle, UInt32 page, void *p_buf, UInt32 p_size, void* s_buf, UInt32 s_size);

/**
 * 写数据到Flash
 * @param handle: 句柄
 * @param page: 页编号
 * @param p_data: 页数据指针
 * @param p_size: 页数据大小, 不能超过Brd_TFlashRawNandInfo.page_size
 * @param s_data: spare数据指针
 * @param s_size: spare数据大小, 不能超过Brd_TFlashRawNandInfo.spare_size
 * @return 当返回值 >= 0 时, 表示实际写入的数据个数 \n
 *         当返回值 < 0 时, 表示写入失败, 参见[brd_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_FlashWriteRawNand(Brd_THandle handle, UInt32 page, void *p_data, UInt32 p_size, void* s_data, UInt32 s_size);

/**
 * 擦除块
 * @param handle: 句柄
 * @param block: 块编号
 * @param count: 块数量
 * @return 当返回值 >= 0 时, 表示擦除成功的块数量 \n
 *         当返回值 < 0 时, 表示擦除失败, 参见[brd_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_FlashEraseRawNandBlock(Brd_THandle handle, UInt32 block, UInt32 count);

#endif  // BRD_FLASH_RAW_NAND

#ifdef __cplusplus
}  ///< extern "C"
#endif

#endif // _BRD_FLASH_H_
/**
 * @} 
 */
